/*
 * Copyright 1993-2009 NVIDIA Corporation.  All rights reserved.
 *
 * NVIDIA Corporation and its licensors retain all intellectual property and 
 * proprietary rights in and to this software and related documentation. 
 * Any use, reproduction, disclosure, or distribution of this software 
 * and related documentation without an express license agreement from
 * NVIDIA Corporation is strictly prohibited.
 *
 * Please refer to the applicable NVIDIA end user license agreement (EULA) 
 * associated with this source code for terms and conditions that govern 
 * your use of this NVIDIA software.
 * 
 */

#ifndef mersennetwister_h
#define mersennetwister_h

enum RAND { ZEROONE, ONEONE, ZEROFIVE };

typedef unsigned int uint32_t;

typedef struct{
    unsigned int matrix_a;
    unsigned int mask_b;
    unsigned int mask_c;
    unsigned int seed;
} mt_struct_stripped;


typedef struct {
    uint32_t aaa;
    int mm,nn,rr,ww;
    uint32_t wmask,umask,lmask;
    int shift0, shift1, shiftB, shiftC;
    uint32_t maskB, maskC;
    int i;
    uint32_t *state;
}mt_struct;


#define MT_RNG_COUNT 4096
#define MT_MM 9
#define MT_NN 19
#define MT_WMASK 0xFFFFFFFFU
#define MT_UMASK 0xFFFFFFFEU
#define MT_LMASK 0x1U
#define MT_SHIFT0 12
#define MT_SHIFTB 7
#define MT_SHIFTC 15
#define MT_SHIFT1 18

//int randSeed = 777;

__global__ void RandomGPU( REAL *d_Random, int mode );

int initRand(int randomNumber);

void seedRand(int seed);

void printRand(int randomNumber,REAL* array,char* namefile);

void FreeRand(void);

void ComputeRandomGPU(int numBlocksRand, int numThreadsPerBlockRand, int mode, REAL* array);

//ceil(a / b)
int iDivUp(int a, int b){ return ((a % b) != 0) ? (a / b + 1) : (a / b); }

//Align a to nearest higher multiple of b
int iAlignUp(int a, int b){ return ((a % b) != 0) ?  (a - a % b + b) : a; }


///////////////////////////////////////////////////////////////////////////////
// Data configuration
///////////////////////////////////////////////////////////////////////////////

REAL *d_aRand;
REAL *d_bRand;
REAL *d_cRand;

REAL *d_Rand;


__device__ static mt_struct_stripped ds_MT[MT_RNG_COUNT];

__device__ int NPerRng;

int RandNumThreadsPerBlock;
int RandNumBlocks;

#endif



